package apobates.gui.formatter.component.progress.crystalBall;

import apobates.gui.formatter.component.progress.ball.BallProgressIndicator;
import apobates.gui.formatter.util.Core;
import javafx.scene.Group;
import javafx.scene.control.Label;
import javafx.scene.control.SkinBase;
import javafx.scene.effect.Blend;
import javafx.scene.effect.BlendMode;
import javafx.scene.effect.Shadow;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.*;

import java.util.List;

/**
 * 进度球皮肤
 * @author xiaofanku
 * @since 20230513
 */
public class CrystalBallProgressIndicatorSkin extends SkinBase<CrystalBallProgressIndicator> {
    private final CrystalBallProgressIndicator indicator;
    private StackPane container = new StackPane();
    // 整体轮廓
    private Circle outlineCir = new Circle();
    // 进度值
    private final Label percentLabel = new Label();
    // 计算进度着色区域
    // 进度着色(圆的一部分)
    private Path paintPath = new Path();
    // 正弦波线深度
    // private int wavyDeep = 5;
    // 波峰
    // private int wavySize = 3;
    /**
     * Constructor for all SkinBase instances.
     *
     * @param control The control for which this Skin should attach to.
     */
    public CrystalBallProgressIndicatorSkin(CrystalBallProgressIndicator control) {
        super(control);
        this.indicator = control;
        initContainer(control);
        initStyles();
        getChildren().add(this.container);
        // 更新进度
        this.indicator.progressProperty().addListener((o, oldVal, newVal) -> {
            // System.out.println("[BPS]new value:"+newVal.intValue()+", old value:"+oldVal.intValue());
            /* 更新进度值(0-100) */
            setProgressLabel(newVal.intValue());
            // 更新着色区域(总高度 * (100 - 进度值) / 100 )
            double v = this.container.getHeight() * ((100 - newVal.intValue()) / 100.0);
            this.updateWaterline(v, newVal.intValue());
        });
    }

    // 初始化组件
    private void initContainer(CrystalBallProgressIndicator control){
        double widthPrefSize = control.getPrefWidth();
        double heightPrefSize = control.getPrefHeight();
        // 整体轮廓
        this.outlineCir.setCenterX(widthPrefSize/2);
        this.outlineCir.setCenterY(heightPrefSize/2);
        this.outlineCir.setRadius(widthPrefSize/2);
        // 进度Path绘制
        Group progressPath = new Group(this.outlineCir);
        progressPath.getChildren().addAll(List.of(this.paintPath));
        // 堆叠Shape和outlineCir
        this.container.setPrefWidth(widthPrefSize);
        this.container.setPrefHeight(heightPrefSize);
        this.container.setMaxWidth(widthPrefSize);
        this.container.setMaxHeight(heightPrefSize);
        this.container.getChildren().addAll(progressPath, percentLabel);
    }
    // 使用样式文件更新组件
    private void initStyles(){
        // 填充
        // this.wavyPath.getStyleClass().add("ballindicator-filler-circle");
        this.paintPath.getStyleClass().add("ballindicator-filler-circle");
        // 边框
        this.outlineCir.getStyleClass().add("ballindicator-border-circle");
        // 进度值
        this.percentLabel.getStyleClass().add("ballindicator-label");
        // 颜色调和
        Blend blend = new Blend();
        // 方案2
        blend.setTopInput(new Shadow(0.5f, Core.toColor("#000000")));
        blend.setMode(BlendMode.ADD);
        this.percentLabel.setEffect(blend);
    }
    // 更新进度球水平线

    /**
     * 更新进度球水平线
     * @param height 非进度高度以外的高度. 例: 进度等于40. 总高度等于200。 参数值=160
     * @param progressValue 进度值. 例:30
     */
    private void updateWaterline(double height, int progressValue){
        System.out.println("[CBPS]progress:" +progressValue+", empty height: "+height);
        // ------------------------------------------------------->
        // 清空原来的
        this.paintPath.getElements().clear();
        // ------------------------------------------------------->
        // 高度的合理区间
        // 增长
        // 防止变型(衰减)
        if(height > this.container.getMaxHeight()){
            System.out.println("[CBPS]height is full break!");
            return;
        }
        if(progressValue == 0){
            System.out.println("[CBPS]progress is low break!!");
            return;
        }
        double widthPrefSize = this.indicator.getPrefWidth();
        double heightPrefSize = this.indicator.getPrefHeight();
        System.out.println("[CBPS]controller width: "+widthPrefSize+", height: "+heightPrefSize);
        // 计算进度着色区域
        // 笔刷
        // 路径内填充
        // 计算当前值在进度条中高度
        double currentHeight = height;
        // 圆的半径
        double radius = widthPrefSize/2;
        // 移动到左下角起始点
        // 指定进度时圆内的宽度
        double waveWidth = calcProcessDiameter(progressValue, widthPrefSize, radius);
        // 起始点在哪
        double offsetSize = radius - (waveWidth / 2);
        System.out.println("current process wave width:"+waveWidth+", offset size:"+offsetSize);
        // 从圆形底部中点起始
        this.paintPath.getElements().add(new MoveTo(widthPrefSize/2, heightPrefSize));
        this.paintPath.getElements().add(this.origin(offsetSize, currentHeight, radius));
        /* 循环的波长 */
        double wavyLength = waveWidth+offsetSize;
        this.paintPath.getElements().add(new LineTo(wavyLength, currentHeight));
        this.paintPath.getElements().add(this.closure(radius));
        // ------------------------------------------------------->
    }
    // 更新进度值
    private void setProgressLabel(int value) {
        if (value >= 0) {
            percentLabel.setText(String.format("%d%%", value));
        }
    }
    /**
     * 从圆的底部中心往进度的高度绘制
     * @param offsetSize X轴
     * @param currentHeight Y轴
     * @param radius 半径
     * @return
     */
    private ArcTo origin(double offsetSize, double currentHeight, double radius){
        ArcTo ins = new ArcTo(); // new ArcTo(100.0, 100.0, curAngle, offsetSize, currentHeight, false, false);
        ins.setRadiusX(radius);
        ins.setRadiusY(radius);
        ins.setX(offsetSize);ins.setY(currentHeight);
        //
        // ins.setXAxisRotation(curAngle);
        ins.setLargeArcFlag(false);
        ins.setSweepFlag(true);
        return ins;
    }

    /**
     * 从圆进度的高度到底部中心绘制
     * @param radius 半径
     * @return
     */
    private ArcTo closure(double radius){
        ArcTo ins = new ArcTo(); //(100.0, 100.0, curAngle, 0, 100, true, true)
        ins.setRadiusX(radius);
        ins.setRadiusY(radius);
        ins.setX(radius);ins.setY(radius*2);
        //
        // ins.setXAxisRotation(curAngle);
        ins.setLargeArcFlag(false);
        ins.setSweepFlag(true);
        return ins;
    }

    /**
     * 计算指定进度值时圆内的直径
     * @param processVal 进度值
     * @param circleDiameter 圆的直径
     * @param circleRadius 圆的半径
     * @return
     */
    public static double calcProcessDiameter(int processVal, double circleDiameter, double circleRadius){
        // i=进度值
        // 进度所占的高度(1-10/100)*200=180
        double emptyHight = (1-processVal/100.0)*circleDiameter;
        // 进度所占的高度
        double dwHight = (circleDiameter - emptyHight);
        // 根据勾股定理算出当前进度所在圆的直径
        double tmp = circleRadius-dwHight;
        double i2 = circleRadius*circleRadius - tmp*tmp;
        //
        double progessWidth = Math.sqrt(i2) * 2;
        System.out.println("process height="+dwHight+", empty height="+emptyHight+", process="+processVal+", waterline="+progessWidth);
        return progessWidth;
    }
}
